package com.gitee.ywj1352.client.proxy;

import com.gitee.ywj1352.client.ClientParser;
import com.gitee.ywj1352.client.RequestPendingCenter;
import com.gitee.ywj1352.client.YWJResultFuture;
import com.gitee.ywj1352.client.exchange.NettyExchangeClient;
import com.gitee.ywj1352.common.message.ClientOp;
import com.gitee.ywj1352.common.util.ClientStructure;
import com.gitee.ywj1352.common.util.IdUtil;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.concurrent.TimeUnit;

public class JdkProxy {
    ClientParser clientParser;

    public <T> T getProxy(NettyExchangeClient nettyExchangeClient, Class<T> interfaces, RequestPendingCenter requestPendingCenter) {
        YWJInvokerInvocationHandler ywjInvokerInvocationHandler = new YWJInvokerInvocationHandler(nettyExchangeClient, clientParser.parse(interfaces), requestPendingCenter);
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{interfaces}, ywjInvokerInvocationHandler);
    }

    class YWJInvokerInvocationHandler implements InvocationHandler {
        private NettyExchangeClient nettyExchangeClient;
        private ClientStructure clientStructure;
        private RequestPendingCenter requestPendingCenter;

        public YWJInvokerInvocationHandler(NettyExchangeClient nettyExchangeClient, ClientStructure clientStructure, RequestPendingCenter requestPendingCenter) {
            this.nettyExchangeClient = nettyExchangeClient;
            this.clientStructure = clientStructure;
            this.requestPendingCenter = requestPendingCenter;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            long streamId = IdUtil.nextId();
            ClientOp clientOp = new ClientOp(streamId, method.getName(), clientStructure, args);
            YWJResultFuture resultFuture = new YWJResultFuture();
            requestPendingCenter.add(streamId, resultFuture);
            nettyExchangeClient.execute(clientOp);
            return resultFuture.get(500, TimeUnit.MILLISECONDS);
        }
    }
}
